package com.shengqin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shengqin.controller.api.dto.BmiStatisticsDTO;
import com.shengqin.controller.api.dto.SchoolTestStatisticsDTO;
import com.shengqin.controller.api.dto.ProjectTestStatisticsDTO;
import com.shengqin.controller.api.dto.ProjectSchoolStatisticsDTO;
import com.shengqin.entity.SummaryResult;
import com.shengqin.entity.TestResult;
import com.shengqin.service.ISchoolService;
import com.shengqin.service.ITestStatisticsService;
import com.shengqin.service.ISummaryResultService;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.borders.SolidBorder;
import com.itextpdf.layout.properties.HorizontalAlignment;
import com.itextpdf.layout.properties.VerticalAlignment;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.layout.renderer.IRenderer;
import com.itextpdf.layout.element.AreaBreak;
import com.itextpdf.layout.properties.AreaBreakType;
import com.shengqin.utils.GradeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.io.ByteArrayOutputStream;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.io.IOException;
import com.shengqin.entity.School;

@Service
public class TestStatisticsServiceImpl implements ITestStatisticsService {

    @Autowired
    private ISummaryResultService summaryResultService;

    @Autowired
    private ISchoolService schoolService;

    private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00");
    // 定义表格样式常量
    private static final DeviceRgb HEADER_BACKGROUND = new DeviceRgb(242, 243, 245);
    private static final DeviceRgb BORDER_COLOR = new DeviceRgb(200, 200, 200);
    private static final DeviceRgb PERCENTAGE_BACKGROUND = new DeviceRgb(245, 249, 253); // 更深的背景色
    private static final float BORDER_WIDTH = 0.5f;
    private static final float CELL_PADDING = 5f;

    // 定义环形进度条颜色
    private static final DeviceRgb[] PROGRESS_COLORS = {
        new DeviceRgb(91, 155, 213),   // 蓝色
        new DeviceRgb(255, 192, 0),    // 黄色
        new DeviceRgb(112, 173, 71),   // 绿色
        new DeviceRgb(237, 125, 49),   // 橙色
        new DeviceRgb(165, 165, 165),  // 灰色
        new DeviceRgb(68, 114, 196),   // 深蓝色
        new DeviceRgb(153, 115, 0),    // 棕色
        new DeviceRgb(68, 84, 106)     // 藏青色
    };

    private static final float CIRCLE_SIZE = 12f;  // 环形进度条的大小
    private static final float CIRCLE_STROKE = 2f;  // 环形进度条的线条粗细
    private static final DeviceRgb CIRCLE_COLOR = new DeviceRgb(0, 176, 240);  // 进度条颜色
    private static final DeviceRgb CIRCLE_BG_COLOR = new DeviceRgb(217, 217, 217);  // 进度条背景色

    private static final DeviceRgb[] BMI_CHART_COLORS = {
        new DeviceRgb(255, 99, 71),    // 肥胖 - 红色
        new DeviceRgb(255, 165, 0),    // 超重 - 橙色
        new DeviceRgb(60, 179, 113),   // 正常 - 绿色
        new DeviceRgb(30, 144, 255)    // 低体重 - 蓝色
    };

    private static final Logger log = LoggerFactory.getLogger(TestStatisticsServiceImpl.class);

    @Override
    public List<SchoolTestStatisticsDTO> getSchoolTestStatistics(Integer planId, Integer schoolId) {
        Assert.notNull(planId, "计划ID不能为空");
        if (schoolId != null) {
            Assert.notNull(schoolService.getById(schoolId), "学校不存在");
        }
        
        // 构建查询条件
        LambdaQueryWrapper<SummaryResult> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SummaryResult::getPlanId, planId);
        if (schoolId != null) {
            wrapper.eq(SummaryResult::getSchoolId, schoolId);
        }
        
        // 获取所有测试结果
        List<SummaryResult> allResults = summaryResultService.list(wrapper);
        
        // 根据schoolId决定按学校还是按年级分组
        Map<String, List<SummaryResult>> groupedResults;
        if (schoolId != null) {
            // 按年级分组，使用年级名称
            groupedResults = allResults.stream()
                    .collect(Collectors.groupingBy(r -> GradeUtil.getGradeName(r.getGradeId())));
        } else {
            // 按学校分组
            groupedResults = allResults.stream()
                    .collect(Collectors.groupingBy(SummaryResult::getSchoolName));
        }
        
        List<SchoolTestStatisticsDTO> statistics = new ArrayList<>();
        
        // 处理每个分组的统计数据
        for (Map.Entry<String, List<SummaryResult>> entry : groupedResults.entrySet()) {
            String groupKey = entry.getKey();
            List<SummaryResult> results = entry.getValue();
            
            SchoolTestStatisticsDTO dto = new SchoolTestStatisticsDTO();
            dto.setSchoolName(groupKey);
            
            // 初始化所有计数字段为0
            dto.setMaleExcellentCount(0);
            dto.setMaleGoodCount(0);
            dto.setMalePassCount(0);
            dto.setMaleFailCount(0);
            dto.setFemaleExcellentCount(0);
            dto.setFemaleGoodCount(0);
            dto.setFemalePassCount(0);
            dto.setFemaleFailCount(0);
            dto.setExcellentTotalCount(0);
            dto.setGoodTotalCount(0);
            dto.setPassTotalCount(0);
            dto.setFailTotalCount(0);
            
            if (schoolId != null) {
                try {
                    int gradeId = Integer.parseInt(groupKey.replaceAll("[^0-9]", ""));
                    dto.setGradeId(gradeId);
                } catch (NumberFormatException e) {
                    log.warn("Failed to parse grade ID from {}", groupKey);
                }
            }
            
            // 统计性别数据
            long maleCount = results.stream().filter(r -> "1".equals(r.getSex())).count();
            long femaleCount = results.stream().filter(r -> "2".equals(r.getSex())).count();
            
            dto.setMaleTotalCount((int) maleCount);
            dto.setFemaleTotalCount((int) femaleCount);
            dto.setTotalCount((int) (maleCount + femaleCount));
            
            // 统计免测人数
            long maleExemptCount = results.stream()
                    .filter(r -> "1".equals(r.getSex()) && isExempt(r))
                    .count();
            long femaleExemptCount = results.stream()
                    .filter(r -> "2".equals(r.getSex()) && isExempt(r))
                    .count();
            
            dto.setMaleExemptCount((int) maleExemptCount);
            dto.setFemaleExemptCount((int) femaleExemptCount);
            dto.setExemptTotalCount((int) (maleExemptCount + femaleExemptCount));
            
            // 计算实测人数
            dto.setMaleTestedCount(dto.getMaleTotalCount() - dto.getMaleExemptCount());
            dto.setFemaleTestedCount(dto.getFemaleTotalCount() - dto.getFemaleExemptCount());
            dto.setTestedTotalCount(dto.getTotalCount() - dto.getExemptTotalCount());
            
            // 计算免测率（使用总人数作为分母）
            if (dto.getTotalCount() > 0) {
                dto.setExemptRate((double) dto.getExemptTotalCount() / dto.getTotalCount() * 100);
            }
            
            // 统计各等级人数（只统计已测试的学生）
            List<SummaryResult> validResults = results.stream()
                    .filter(r -> !isExempt(r) && r.getTotalLevel() != null)
                    .collect(Collectors.toList());
            
            // 按性别统计各等级人数
            for (SummaryResult result : validResults) {
                String sex = result.getSex();
                String level = result.getTotalLevel();
                
                if ("1".equals(sex)) { // 男生
                    switch (level) {
                        case "优秀": 
                            dto.setMaleExcellentCount(dto.getMaleExcellentCount() == null ? 1 : dto.getMaleExcellentCount() + 1); 
                            break;
                        case "良好": 
                            dto.setMaleGoodCount(dto.getMaleGoodCount() == null ? 1 : dto.getMaleGoodCount() + 1); 
                            break;
                        case "及格": 
                            dto.setMalePassCount(dto.getMalePassCount() == null ? 1 : dto.getMalePassCount() + 1); 
                            break;
                        case "不及格": 
                            dto.setMaleFailCount(dto.getMaleFailCount() == null ? 1 : dto.getMaleFailCount() + 1); 
                            break;
                    }
                } else if ("2".equals(sex)) { // 女生
                    switch (level) {
                        case "优秀": 
                            dto.setFemaleExcellentCount(dto.getFemaleExcellentCount() == null ? 1 : dto.getFemaleExcellentCount() + 1); 
                            break;
                        case "良好": 
                            dto.setFemaleGoodCount(dto.getFemaleGoodCount() == null ? 1 : dto.getFemaleGoodCount() + 1); 
                            break;
                        case "及格": 
                            dto.setFemalePassCount(dto.getFemalePassCount() == null ? 1 : dto.getFemalePassCount() + 1); 
                            break;
                        case "不及格": 
                            dto.setFemaleFailCount(dto.getFemaleFailCount() == null ? 1 : dto.getFemaleFailCount() + 1); 
                            break;
                    }
                }
            }
            
            // 计算各等级总人数
            dto.setExcellentTotalCount((dto.getMaleExcellentCount() == null ? 0 : dto.getMaleExcellentCount()) + 
                                     (dto.getFemaleExcellentCount() == null ? 0 : dto.getFemaleExcellentCount()));
            dto.setGoodTotalCount((dto.getMaleGoodCount() == null ? 0 : dto.getMaleGoodCount()) + 
                                (dto.getFemaleGoodCount() == null ? 0 : dto.getFemaleGoodCount()));
            dto.setPassTotalCount((dto.getMalePassCount() == null ? 0 : dto.getMalePassCount()) + 
                                (dto.getFemalePassCount() == null ? 0 : dto.getFemalePassCount()));
            dto.setFailTotalCount((dto.getMaleFailCount() == null ? 0 : dto.getMaleFailCount()) + 
                                (dto.getFemaleFailCount() == null ? 0 : dto.getFemaleFailCount()));
            
            // 计算比率（使用实测人数作为分母）
            if (dto.getTestedTotalCount() > 0) {
                dto.setExcellentRate((double) dto.getExcellentTotalCount() / dto.getTestedTotalCount() * 100);
                dto.setGoodRate((double) dto.getGoodTotalCount() / dto.getTestedTotalCount() * 100);
                dto.setPassRate((double) dto.getPassTotalCount() / dto.getTestedTotalCount() * 100);
                dto.setFailRate((double) dto.getFailTotalCount() / dto.getTestedTotalCount() * 100);
                dto.setQualifiedRate((double) (dto.getExcellentTotalCount() + dto.getGoodTotalCount() + 
                                   dto.getPassTotalCount()) / dto.getTestedTotalCount() * 100);
            }
            
            // 计算平均分（只计算已测试的学生）
            double maleAvgScore = results.stream()
                    .filter(r -> "1".equals(r.getSex()) && !isExempt(r) && r.getTotalScore() != null)
                    .mapToDouble(r -> r.getTotalScore().doubleValue())
                    .average()
                    .orElse(0);
            
            double femaleAvgScore = results.stream()
                    .filter(r -> "2".equals(r.getSex()) && !isExempt(r) && r.getTotalScore() != null)
                    .mapToDouble(r -> r.getTotalScore().doubleValue())
                    .average()
                    .orElse(0);
            
            double totalAvgScore = results.stream()
                    .filter(r -> !isExempt(r) && r.getTotalScore() != null)
                    .mapToDouble(r -> r.getTotalScore().doubleValue())
                    .average()
                    .orElse(0);
            
            dto.setMaleAvgScore(maleAvgScore);
            dto.setFemaleAvgScore(femaleAvgScore);
            dto.setTotalAvgScore(totalAvgScore);
            
            // 记录统计日志
            log.debug("School {} statistics: total={}, tested={}, exempt={}, excellent={}, good={}, pass={}, fail={}", 
                dto.getSchoolName(), dto.getTotalCount(), dto.getTestedTotalCount(), dto.getExemptTotalCount(),
                dto.getExcellentTotalCount(), dto.getGoodTotalCount(), dto.getPassTotalCount(), dto.getFailTotalCount());
            
            statistics.add(dto);
        }
        
        // 如果是按年级统计，则按年级排序
        if (schoolId != null) {
            Map<String, Integer> gradeOrder = new HashMap<>();
            gradeOrder.put("初一", 1);
            gradeOrder.put("初二", 2);
            gradeOrder.put("初三", 3);
            
            statistics.sort((a, b) -> {
                int orderA = gradeOrder.getOrDefault(a.getSchoolName(), Integer.MAX_VALUE);
                int orderB = gradeOrder.getOrDefault(b.getSchoolName(), Integer.MAX_VALUE);
                return Integer.compare(orderA, orderB);
            });
        }
        
        return statistics;
    }

    /**
     * 判断学生是否免测
     * 当test_result_list中所有项的result都为空时，视为免测
     */
    private boolean isExempt(SummaryResult result) {
        if (result.getTestResultList() == null) {
            return true; // 没有测试结果视为免测
        }
        
        return result.getTestResultList().stream()
                .allMatch(testResult -> testResult.getResult() == null || 
                         testResult.getResult().trim().isEmpty());
    }

    private void addOverviewPage(Document document) throws IOException {
        // 添加分页
        document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));

        // 添加概述标题
        PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
        Paragraph title = new Paragraph("概述")
                .setFont(font)
                .setFontSize(16)
                .setBold()
                .setTextAlignment(TextAlignment.CENTER)
                .setMarginBottom(20);
        document.add(title);

        // 添加概述内容
        String overview1 = "现阶段，随着我国教育事业的发展和全面健康理念的提出，学生的体质状况得到各方面的广泛重视。虽然《国家学生体质健康标准》的颁布，对学生体质改善起到了一定程度的作用，但也占据了许多问题和不足，学生体质水平仍然呈总体下滑趋势。";
        String overview2 = "近十年来，国家层面相继出台了多项政策，旨在提高我国青少年体质健康水平。2007年2月，中共中央、国务院发布了《关于加强青少年体育、增强青少年体质的意见》；2012年10月，国务院办公厅转发教育部等部门《关于进一步加强学校体育工作的若干意见》的通知；2014年4月，教育部先后印发《学生体质健康监测评价办法》、《中小学体育工作评估办法》、《学校体育工作年度报告办法》等三个文件的通知，进一步密实和推进我国青少年体质健康监测体系，提升青少年体质健康水平。";
        String overview3 = "为贯彻党的十八届三中全会提出的\"强化体育课和课外锻炼，促进青少年身心健康、体魄强健\"的精神，认真落实\"健康第一\"的指导思想，积极开展学生体质健康测试活动。";
        String overview4 = "因此，加强对青少年体质的研究，用科学的指标评价青少年的体质状况，进而不断改善和增强青少年的体质，已成为现在有关部门监测中小学生体质状况的主要手段。";

        String[] paragraphs = {overview1, overview2, overview3, overview4};

        for (String paragraph : paragraphs) {
            document.add(new Paragraph(paragraph)
                    .setFont(font)
                    .setFontSize(12)
                    .setTextAlignment(TextAlignment.JUSTIFIED)
                    .setMarginBottom(10)
                    .setFirstLineIndent(24)); // 设置首行缩进
        }

        // 添加评价标准小节
        Paragraph standardTitle = new Paragraph("评价标准")
                .setFont(font)
                .setFontSize(14)
                .setBold()
                .setMarginTop(20)
                .setMarginBottom(10);
        document.add(standardTitle);

        // 添加评价标准内容
        String[] standards = {
            "1. 《国家学生体质健康标准》（以下简称《标准》）是国家学校教育工作的基础性指导文件和教育质量基本标准，是评价学生综合素质、评估学校工作和衡量各地教育发展的重要依据，是《国家体育锻炼标准》在学校的具体实施，适用于全日制普通小学、初中、普通高中、中等职业学校、普通高等学校的学生。",
            
            "2. 本标准的修订坚持健康第一，落实《国家中长期教育改革和发展规划纲要（2010-2020年）》、《国务院办公厅转发教育部等部门〈关于进一步加强学校体育工作若干意见〉的通知》（国办发〔2012〕53号）和《教育部关于印发〈学生体质健康监测评价办法〉等三个文件的通知》（教体艺〔2014〕3号）有关要求，着重提高《标准》应用的信度、效度和区分度，着重强化其教育激励、反馈调整和引导锻炼的功能，着重提高其教育监测和效评价的支撑能力。",
            
            "3. 本标准从身体形态、身体机能和身体素质等方面综合评定学生的体质健康水平，是促进学生体质健康发展、激励学生积极进行身体锻炼的教育手段，是国家学生发展核心素养体系和学业质量标准的重要组成部分，是学生体质健康的个体评价标准。",
            
            "4. 本标准将适用对象划分为以下组别：小学、初中、高中按每个年级为一组，其中小学为6组、初中为3组、高中为3组、大学一、二年级为一组，三、四年级为一组。",
            
            "5. 小学、初中、高中、大学各组别的测试指标均为必测指标。其中，身体形态类中的身高、体重，身体机能类的肺活量，以及身体素质类中的50米跑、坐位体前屈为各年级学生共性指标。",
            
            "6. 本标准的学年总分由标准分与附加分之和组成，满分为120分，标准分由各单项指标得分与权重乘积之和组成，满分为100分；附加分根据实测成绩确定，即对成绩超过100分的加分指标进行加分，满分为20分；小学的加分指标为1分钟跳绳，加分幅度最大为20分；初中、高中和大学的加分指标为男生引体向上和1000米跑，女生1分钟仰卧起坐和800米跑，各指标加分幅度最大为为10分。",
            
            "7. 根据学生学年总分评定等级：90.0分及以上为优秀，80.0～89.9分为良好，60.0～79.9分为及格，59.9分及以下为不及格。"
        };

        for (String standard : standards) {
            document.add(new Paragraph(standard)
                    .setFont(font)
                    .setFontSize(12)
                    .setTextAlignment(TextAlignment.JUSTIFIED)
                    .setMarginBottom(10)
                    .setFirstLineIndent(24));
        }
    }

    @Override
    public byte[] generateTestStatisticsPDF(Integer planId, Integer schoolId) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PdfWriter writer = new PdfWriter(baos);
            PdfDocument pdf = new PdfDocument(writer);
            pdf.setDefaultPageSize(PageSize.A4.rotate()); // 使用横向A4纸
            Document document = new Document(pdf);
            document.setMargins(20, 20, 20, 20); // 设置页面边距

            // 设置中文字体
            PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
            document.setFont(font);
            document.setFontSize(10);

            // 添加一个空白段落以确保第一页被创建
            document.add(new Paragraph(""));

            // 添加封面
            addCoverPage(document, schoolId);
            
            // 添加概述页面
            addOverviewPage(document);
            
            // 添加分隔页
            document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));

            // 获取学校统计数据
            List<SchoolTestStatisticsDTO> schoolStats = getSchoolTestStatistics(planId, schoolId);
            boolean isGradeLevel = schoolId != null;

            // 添加第一个表格：学生人数统计
            addStudentCountTable(document, schoolStats, isGradeLevel);
            
            // 添加分隔空间
            document.add(new Paragraph().setMarginBottom(30));
            
            // 添加第二个表格：等级分布统计
            addGradeDistributionTable(document, schoolStats, isGradeLevel);

            // 添加分隔空间
            document.add(new Paragraph().setMarginBottom(30));
            
            // 添加第三个表格：平均分统计
            addAverageScoreTable(document, schoolStats, isGradeLevel);

            // 添加分隔空间
            document.add(new Paragraph().setMarginBottom(30));

            // 获取项目统计数据
            List<ProjectTestStatisticsDTO> projectStats = getProjectTestStatistics(planId, schoolId);
            
            // 添加第四个表格：项目测试人数统计
            addProjectStatisticsTable(document, projectStats);

            // 添加分隔空间
            document.add(new Paragraph().setMarginBottom(30));

            // 添加第五个表格：项目等级分布统计
            addProjectGradeDistributionTable(document, projectStats);

            // 添加分隔空间
            document.add(new Paragraph().setMarginBottom(30));

            // 获取项目学校统计数据
            List<ProjectSchoolStatisticsDTO> projectSchoolStats = getProjectSchoolStatistics(planId, schoolId);
            
            // 添加项目学校统计表格
            addProjectSchoolStatisticsTable(document, projectSchoolStats, isGradeLevel);

            // 添加分隔空间
            document.add(new Paragraph().setMarginBottom(30));

            // 获取BMI统计数据
            List<BmiStatisticsDTO> bmiStats = getBmiStatistics(planId, schoolId);
            
            // 添加BMI等级分布统计表
            addBmiDistributionTable(document, bmiStats);

            // 添加分隔空间
            document.add(new Paragraph().setMarginBottom(30));

            // 添加BMI饼图
            addBmiPieCharts(document, bmiStats, isGradeLevel);

            document.close();
            return baos.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("生成PDF报告失败", e);
        }
    }

    private void addCoverPage(Document document, Integer schoolId) throws IOException {
        // 获取页面尺寸
        Rectangle pageSize = document.getPdfDocument().getDefaultPageSize();
        PdfCanvas canvas = new PdfCanvas(document.getPdfDocument().getFirstPage());
        
        // 创建渐变背景
        float height = pageSize.getHeight();
        float width = pageSize.getWidth();
        
        // 绘制渐变背景
        float[] startColor = {235, 245, 255};  // 浅蓝色
        float[] endColor = {255, 255, 255};    // 白色
        
        int steps = 100;
        for (int i = 0; i < steps; i++) {
            float ratio = (float) i / steps;
            int r = (int) (startColor[0] + (endColor[0] - startColor[0]) * ratio);
            int g = (int) (startColor[1] + (endColor[1] - startColor[1]) * ratio);
            int b = (int) (startColor[2] + (endColor[2] - startColor[2]) * ratio);
            
            canvas.setFillColor(new DeviceRgb(r, g, b))
                  .rectangle(0, height * (1 - ratio), width, height / steps)
                  .fill();
        }
        
        // 添加装饰图案
        float decorSize = 100f;
        DeviceRgb decorColor = new DeviceRgb(91, 155, 213);
        
        // 左上角装饰
        canvas.setFillColor(decorColor)
              .moveTo(0, height)
              .lineTo(decorSize, height)
              .lineTo(0, height - decorSize)
              .fill();
              
        // 右下角装饰
        canvas.setFillColor(decorColor)
              .moveTo(width, 0)
              .lineTo(width - decorSize, 0)
              .lineTo(width, decorSize)
              .fill();
        
        // 获取学校名称
        String schoolName = "";
        if (schoolId != null) {
            // 使用 schoolService.getById() 获取学校名称
            schoolName = getSchoolNameById(schoolId);
        }
        
        // 添加标题
        PdfFont titleFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
        // 添加学校名称
        if (!schoolName.isEmpty()) {
            Paragraph schoolNameParagraph = new Paragraph(schoolName)
                    .setFont(titleFont)
                    .setFontSize(36)
                    .setBold()
                    .setTextAlignment(TextAlignment.CENTER)
                    .setMarginTop(height / 3)
                    .setFontColor(new DeviceRgb(51, 51, 51));
            document.add(schoolNameParagraph);
        }

        // 添加报告标题
        Paragraph title = new Paragraph("学生体质健康测试分析报告")
                .setFont(titleFont)
                .setFontSize(36)
                .setBold()
                .setTextAlignment(TextAlignment.CENTER)
                .setMarginTop(10) // 设置与学校名称的间距
                .setFontColor(new DeviceRgb(51, 51, 51));
        document.add(title);
        
        // 添加装饰线
        float lineWidth = 200f;
        float lineY = height / 3 - 50;
        canvas.setStrokeColor(decorColor)
              .setLineWidth(2)
              .moveTo((width - lineWidth) / 2, lineY)
              .lineTo((width + lineWidth) / 2, lineY)
              .stroke();
        
        // 添加日期
        Paragraph date = new Paragraph(new java.text.SimpleDateFormat("yyyy年MM月").format(new Date()))
                .setFont(titleFont)
                .setFontSize(14)
                .setTextAlignment(TextAlignment.CENTER)
                .setMarginTop(50)
                .setFontColor(new DeviceRgb(102, 102, 102));
        
        document.add(date);
    }

    private void addStudentCountTable(Document document, List<SchoolTestStatisticsDTO> statistics, boolean isGradeLevel) {
        // 添加第一个表格的标题
        String titleText = isGradeLevel ? "各年级测试人数及免测人数统计表" : "各学校测试人数及免测人数统计表";
        Paragraph title1 = new Paragraph(titleText)
                .setFontSize(16)
                .setTextAlignment(TextAlignment.CENTER)
                .setBold()
                .setMarginBottom(20);
        document.add(title1);

        // 创建第一个表格
        float[] columnWidths1 = {200, 60, 60, 80, 60, 60, 80, 60, 60, 80, 60};
        Table table1 = new Table(UnitValue.createPointArray(columnWidths1));
        table1.setWidth(UnitValue.createPercentValue(100))
            .setHorizontalAlignment(HorizontalAlignment.CENTER)
            .setMarginTop(10)
            .setMarginBottom(10);

        // 添加表头
        addStudentCountTableHeader(table1, isGradeLevel);

        // 添加数据行
        for (SchoolTestStatisticsDTO stat : statistics) {
            addStudentCountTableRow(table1, stat);
        }

        document.add(table1);
    }

    private void addGradeDistributionTable(Document document, List<SchoolTestStatisticsDTO> statistics, boolean isGradeLevel) {
        // 添加第二个表格的标题
        String titleText = isGradeLevel ? "各年级测试等级分布统计表" : "各学校测试等级分布统计表";
        Paragraph title2 = new Paragraph(titleText)
                .setFontSize(16)
                .setTextAlignment(TextAlignment.CENTER)
                .setBold()
                .setMarginBottom(20);
        document.add(title2);

        // 创建第二个表格
        float[] columnWidths2 = {200, 60, 60, 60, 40, 60, 60, 60, 40, 60, 60, 60, 40, 60, 60, 60, 40};
        Table table2 = new Table(UnitValue.createPointArray(columnWidths2));
        table2.setWidth(UnitValue.createPercentValue(100))
            .setHorizontalAlignment(HorizontalAlignment.CENTER)
            .setMarginTop(10)
            .setMarginBottom(10);

        // 添加表头
        addGradeDistributionTableHeader(table2, isGradeLevel);

        // 添加数据行
        for (SchoolTestStatisticsDTO stat : statistics) {
            addGradeDistributionTableRow(table2, stat);
        }

        document.add(table2);
    }

    private void addStudentCountTableHeader(Table table, boolean isGradeLevel) {
        // 第一行表头
        table.addCell(createHeaderCell(isGradeLevel ? "年级" : "学校名称", 2, 1));
        table.addCell(createHeaderCell("学生人数", 1, 3));
        table.addCell(createHeaderCell("实测学生数", 1, 3));
        table.addCell(createHeaderCell("申请免测学生数", 1, 4));
//        table.addCell(createHeaderCell("占%", 2, 1));

        // 第二行表头
        String[] headers = {"男", "女", "合计", "男", "女", "合计", "男", "女", "合计","占%"};
        for (String header : headers) {
            table.addCell(createHeaderCell(header, 1, 1));
        }
    }

    private void addGradeDistributionTableHeader(Table table, boolean isGradeLevel) {
        // 第一行表头
        table.addCell(createHeaderCell(isGradeLevel ? "年级" : "单位", 2, 1));
        table.addCell(createHeaderCell("优秀人数", 1, 4));
        table.addCell(createHeaderCell("良好人数", 1, 4));
        table.addCell(createHeaderCell("及格人数", 1, 4));
        table.addCell(createHeaderCell("不及格人数", 1, 4));

        // 第二行表头
        String[] subHeaders = {"男", "女", "合计", "占%"};
        for (int i = 0; i < 4; i++) {
            for (String header : subHeaders) {
                table.addCell(createHeaderCell(header, 1, 1));
            }
        }
    }

    private void addStudentCountTableRow(Table table, SchoolTestStatisticsDTO stat) {
        // 添加学校名称
        table.addCell(createCell(stat.getSchoolName()));

        // 添加学生人数
        table.addCell(createCell(String.valueOf(stat.getMaleTotalCount())));
        table.addCell(createCell(String.valueOf(stat.getFemaleTotalCount())));
        table.addCell(createCell(String.valueOf(stat.getTotalCount())));

        // 添加实测学生数
        table.addCell(createCell(String.valueOf(stat.getMaleTestedCount())));
        table.addCell(createCell(String.valueOf(stat.getFemaleTestedCount())));
        table.addCell(createCell(String.valueOf(stat.getTestedTotalCount())));

        // 添加免测学生数
        table.addCell(createCell(String.valueOf(stat.getMaleExemptCount())));
        table.addCell(createCell(String.valueOf(stat.getFemaleExemptCount())));
        table.addCell(createCell(String.valueOf(stat.getExemptTotalCount())));

        // 添加免测率，使用formatPercentage方法处理可能为空的值
        table.addCell(createPercentageCell(formatPercentage(stat.getExemptRate())));
    }

    private void addGradeDistributionTableRow(Table table, SchoolTestStatisticsDTO stat) {
        // 添加学校名称
        table.addCell(createCell(stat.getSchoolName()));

        // 计算各等级比率（使用总人数作为分母）
        double totalCount = stat.getTotalCount();
        double excellentRate = totalCount > 0 ? stat.getExcellentTotalCount() * 100.0 / totalCount : 0;
        double goodRate = totalCount > 0 ? stat.getGoodTotalCount() * 100.0 / totalCount : 0;
        double passRate = totalCount > 0 ? stat.getPassTotalCount() * 100.0 / totalCount : 0;
        double failRate = totalCount > 0 ? stat.getFailTotalCount() * 100.0 / totalCount : 0;

        // 添加优秀人数
        table.addCell(createCell(String.valueOf(stat.getMaleExcellentCount())));
        table.addCell(createCell(String.valueOf(stat.getFemaleExcellentCount())));
        table.addCell(createCell(String.valueOf(stat.getExcellentTotalCount())));
        table.addCell(createPercentageCell(DECIMAL_FORMAT.format(excellentRate) + "%"));

        // 添加良好人数
        table.addCell(createCell(String.valueOf(stat.getMaleGoodCount())));
        table.addCell(createCell(String.valueOf(stat.getFemaleGoodCount())));
        table.addCell(createCell(String.valueOf(stat.getGoodTotalCount())));
        table.addCell(createPercentageCell(DECIMAL_FORMAT.format(goodRate) + "%"));

        // 添加及格人数
        table.addCell(createCell(String.valueOf(stat.getMalePassCount())));
        table.addCell(createCell(String.valueOf(stat.getFemalePassCount())));
        table.addCell(createCell(String.valueOf(stat.getPassTotalCount())));
        table.addCell(createPercentageCell(DECIMAL_FORMAT.format(passRate) + "%"));

        // 添加不及格人数
        table.addCell(createCell(String.valueOf(stat.getMaleFailCount())));
        table.addCell(createCell(String.valueOf(stat.getFemaleFailCount())));
        table.addCell(createCell(String.valueOf(stat.getFailTotalCount())));
        table.addCell(createPercentageCell(DECIMAL_FORMAT.format(failRate) + "%"));
    }

    private Cell createHeaderCell(String text, int rowspan, int colspan) {
        Cell cell = new Cell(rowspan, colspan)
                .add(new Paragraph(text))
                .setBackgroundColor(HEADER_BACKGROUND)
                .setTextAlignment(TextAlignment.CENTER)
                .setVerticalAlignment(VerticalAlignment.MIDDLE)
                .setBold()
                .setPadding(CELL_PADDING)
                .setBorder(new SolidBorder(BORDER_COLOR, BORDER_WIDTH));
        
        // 如果是跨列的表头，设置底部边框加粗
        if (colspan > 1) {
            cell.setBorderBottom(new SolidBorder(BORDER_COLOR, BORDER_WIDTH * 2));
        }
        
        return cell;
    }

    private Cell createPercentageCell(String text) {
        // 解析百分比值
        double percentage = 0;
        try {
            if (text != null && !text.equals("-")) {
                percentage = Double.parseDouble(text.replace("%", ""));
            } else {
                return createCell("-");
            }
        } catch (NumberFormatException e) {
            return createCell(text);
        }

        // 创建一个带有额外左边距的单元格（为进度条预留空间）
        Cell cell = new Cell()
                .setTextAlignment(TextAlignment.CENTER)
                .setVerticalAlignment(VerticalAlignment.MIDDLE)
                .setPadding(CELL_PADDING)
                .setPaddingLeft(CELL_PADDING + CIRCLE_SIZE + 5)  // 额外的左边距用于放置进度条
                .setBorder(new SolidBorder(BORDER_COLOR, BORDER_WIDTH))
                .setBackgroundColor(PERCENTAGE_BACKGROUND);
        
        // 创建一个自定义布局的段落
        Paragraph p = new Paragraph()
                .add(text)
                .setTextAlignment(TextAlignment.CENTER);

        cell.add(p);

        // 随机选择一个颜色
        DeviceRgb progressColor = PROGRESS_COLORS[Math.abs(text.hashCode()) % PROGRESS_COLORS.length];

        // 添加自定义渲染事件来绘制进度条
        cell.setNextRenderer(new CellWithCircularProgressRenderer(cell, percentage, progressColor));
        
        return cell;
    }

    private static class CellWithCircularProgressRenderer extends CellRenderer {
        private final double percentage;
        private final DeviceRgb progressColor;

        public CellWithCircularProgressRenderer(Cell modelElement, double percentage, DeviceRgb progressColor) {
            super(modelElement);
            this.percentage = percentage;
            this.progressColor = progressColor;
        }

        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);

            // 获取单元格的边界
            Rectangle cellRect = getOccupiedArea().getBBox();
            
            // 计算圆的中心位置（在单元格的左侧，垂直居中）
            float centerX = cellRect.getLeft() + CELL_PADDING + CIRCLE_SIZE / 2;
            float centerY = cellRect.getBottom() + (cellRect.getHeight() / 2);
            float radius = CIRCLE_SIZE / 2 - CIRCLE_STROKE / 2;

            PdfCanvas canvas = drawContext.getCanvas();
            
            // 绘制背景圆环
            canvas.saveState()
                  .setStrokeColor(CIRCLE_BG_COLOR)
                  .setLineWidth(CIRCLE_STROKE)
                  .circle(centerX, centerY, radius)
                  .stroke()
                  .restoreState();

            // 如果百分比大于0，绘制进度弧
            if (percentage > 0) {
                canvas.saveState()
                      .setStrokeColor(progressColor)
                      .setLineWidth(CIRCLE_STROKE);

                // 计算弧度
                double angleInRadians = (percentage / 100.0) * Math.PI * 2;
                
                // 绘制进度弧（从12点钟方向开始，顺时针）
                canvas.arc(centerX - radius, centerY - radius, 
                          centerX + radius, centerY + radius, 
                          90, -(float) Math.toDegrees(angleInRadians))
                      .stroke()
                      .restoreState();
            }
        }

        @Override
        public IRenderer getNextRenderer() {
            return new CellWithCircularProgressRenderer((Cell) getModelElement(), percentage, progressColor);
        }
    }

    private Cell createCell(String text) {
        Cell cell = new Cell()
                .add(new Paragraph(text))
                .setTextAlignment(TextAlignment.CENTER)
                .setVerticalAlignment(VerticalAlignment.MIDDLE)
                .setPadding(CELL_PADDING)
                .setBorder(new SolidBorder(BORDER_COLOR, BORDER_WIDTH));

        // 对于百分比类型的单元格，使用带进度条的单元格
        if (text.endsWith("%")) {
            return createPercentageCell(text);
        }
        // 对于其他数字类型的单元格，保持原有的背景色
        else if (text.matches("\\d+(\\.\\d+)?")) {
            cell.setBackgroundColor(new DeviceRgb(252, 252, 252));
        }

        return cell;
    }

    @Override
    public List<ProjectTestStatisticsDTO> getProjectTestStatistics(Integer planId, Integer schoolId) {
        Assert.notNull(planId, "计划ID不能为空");
        
        // 构建查询条件
        LambdaQueryWrapper<SummaryResult> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SummaryResult::getPlanId, planId);
        if (schoolId != null) {
            wrapper.eq(SummaryResult::getSchoolId, schoolId);
        }
        
        // 获取所有测试结果
        List<SummaryResult> allResults = summaryResultService.list(wrapper);
        
        // 创建项目统计结果Map
        Map<String, ProjectTestStatisticsDTO> projectStatsMap = new HashMap<>();
        
        // 定义需要排除的项目名称
        Set<String> excludedProjects = new HashSet<>(Arrays.asList("身高", "体重", "身高体重", "BMI"));
        
        // 处理每个学生的测试结果
        for (SummaryResult result : allResults) {
            if (result.getTestResultList() == null) {
                continue;
            }
            
            // 获取性别
            String sex = result.getSex();
            boolean isMale = "1".equals(sex);
            boolean isFemale = "2".equals(sex);
            
            // 处理每个项目的测试结果
            for (TestResult testResult : result.getTestResultList()) {
                String projectName = testResult.getPrjName();
                
                // 跳过需要排除的项目
                if (excludedProjects.contains(projectName)) {
                    continue;
                }
                
                // 获取或创建项目统计DTO
                ProjectTestStatisticsDTO projectStats = projectStatsMap.computeIfAbsent(
                    projectName,
                    k -> {
                        ProjectTestStatisticsDTO dto = new ProjectTestStatisticsDTO();
                        dto.setProjectName(k);
                        dto.setMaleTotalCount(0);
                        dto.setFemaleTotalCount(0);
                        dto.setTotalCount(0);
                        dto.setMaleTestedCount(0);
                        dto.setFemaleTestedCount(0);
                        dto.setTestedTotalCount(0);
                        dto.setMaleExemptCount(0);
                        dto.setFemaleExemptCount(0);
                        dto.setExemptTotalCount(0);
                        dto.setMaleExcellentCount(0);
                        dto.setFemaleExcellentCount(0);
                        dto.setExcellentTotalCount(0);
                        dto.setMaleGoodCount(0);
                        dto.setFemaleGoodCount(0);
                        dto.setGoodTotalCount(0);
                        dto.setMalePassCount(0);
                        dto.setFemalePassCount(0);
                        dto.setPassTotalCount(0);
                        dto.setMaleFailCount(0);
                        dto.setFemaleFailCount(0);
                        dto.setFailTotalCount(0);
                        return dto;
                    }
                );
                
                // 更新总人数
                if (isMale) {
                    projectStats.setMaleTotalCount(projectStats.getMaleTotalCount() + 1);
                } else if (isFemale) {
                    projectStats.setFemaleTotalCount(projectStats.getFemaleTotalCount() + 1);
                }
                projectStats.setTotalCount(projectStats.getMaleTotalCount() + projectStats.getFemaleTotalCount());
                
                // 更新实测人数和等级统计
                boolean isTested = testResult.getResult() != null && !testResult.getResult().trim().isEmpty();
                if (isTested) {
                    // 更新实测人数
                    if (isMale) {
                        projectStats.setMaleTestedCount(projectStats.getMaleTestedCount() + 1);
                    } else if (isFemale) {
                        projectStats.setFemaleTestedCount(projectStats.getFemaleTestedCount() + 1);
                    }
                    projectStats.setTestedTotalCount(projectStats.getMaleTestedCount() + projectStats.getFemaleTestedCount());

                    // 更新等级统计
                    String level = testResult.getLevel();
                    if (level != null) {
                        switch (level) {
                            case "优秀":
                                if (isMale) projectStats.setMaleExcellentCount(projectStats.getMaleExcellentCount() + 1);
                                else if (isFemale) projectStats.setFemaleExcellentCount(projectStats.getFemaleExcellentCount() + 1);
                                break;
                            case "良好":
                                if (isMale) projectStats.setMaleGoodCount(projectStats.getMaleGoodCount() + 1);
                                else if (isFemale) projectStats.setFemaleGoodCount(projectStats.getFemaleGoodCount() + 1);
                                break;
                            case "及格":
                                if (isMale) projectStats.setMalePassCount(projectStats.getMalePassCount() + 1);
                                else if (isFemale) projectStats.setFemalePassCount(projectStats.getFemalePassCount() + 1);
                                break;
                            case "不及格":
                                if (isMale) projectStats.setMaleFailCount(projectStats.getMaleFailCount() + 1);
                                else if (isFemale) projectStats.setFemaleFailCount(projectStats.getFemaleFailCount() + 1);
                                break;
                        }
                    }
                } else {
                    // 更新免测人数
                    if (isMale) {
                        projectStats.setMaleExemptCount(projectStats.getMaleExemptCount() + 1);
                    } else if (isFemale) {
                        projectStats.setFemaleExemptCount(projectStats.getFemaleExemptCount() + 1);
                    }
                    projectStats.setExemptTotalCount(projectStats.getMaleExemptCount() + projectStats.getFemaleExemptCount());
                }
            }
        }
        
        // 计算各项统计的总数和比率
        for (ProjectTestStatisticsDTO stats : projectStatsMap.values()) {
            // 更新等级总人数
            stats.setExcellentTotalCount(stats.getMaleExcellentCount() + stats.getFemaleExcellentCount());
            stats.setGoodTotalCount(stats.getMaleGoodCount() + stats.getFemaleGoodCount());
            stats.setPassTotalCount(stats.getMalePassCount() + stats.getFemalePassCount());
            stats.setFailTotalCount(stats.getMaleFailCount() + stats.getFemaleFailCount());

            // 计算比率
            if (stats.getTestedTotalCount() > 0) {
                stats.setExcellentRate((double) stats.getExcellentTotalCount() / stats.getTestedTotalCount() * 100);
                stats.setGoodRate((double) stats.getGoodTotalCount() / stats.getTestedTotalCount() * 100);
                stats.setPassRate((double) stats.getPassTotalCount() / stats.getTestedTotalCount() * 100);
                stats.setFailRate((double) stats.getFailTotalCount() / stats.getTestedTotalCount() * 100);
            }

            if (stats.getTotalCount() > 0) {
                stats.setExemptRate((double) stats.getExemptTotalCount() / stats.getTotalCount() * 100);
            }
        }
        
        // 转换为列表并返回
        return new ArrayList<>(projectStatsMap.values());
    }

    private void addProjectGradeDistributionTable(Document document, List<ProjectTestStatisticsDTO> statistics) {
        // 添加表格标题
        Paragraph title = new Paragraph("各个项目测试等级分布统计表")
                .setFontSize(16)
                .setTextAlignment(TextAlignment.CENTER)
                .setBold()
                .setMarginBottom(20);
        document.add(title);

        // 创建表格
        float[] columnWidths = {200, 60, 60, 60, 40, 60, 60, 60, 40, 60, 60, 60, 40, 60, 60, 60, 40};
        Table table = new Table(UnitValue.createPointArray(columnWidths));
        table.setWidth(UnitValue.createPercentValue(100))
            .setHorizontalAlignment(HorizontalAlignment.CENTER)
            .setMarginTop(10)
            .setMarginBottom(10);

        // 添加表头（第一行）
        table.addCell(createHeaderCell("项目名称", 2, 1));
        table.addCell(createHeaderCell("优秀人数", 1, 4));
        table.addCell(createHeaderCell("良好人数", 1, 4));
        table.addCell(createHeaderCell("及格人数", 1, 4));
        table.addCell(createHeaderCell("不及格人数", 1, 4));

        // 添加表头（第二行）
        String[] subHeaders = {"男", "女", "合计", "占%"};
        for (int i = 0; i < 4; i++) {
            for (String header : subHeaders) {
                table.addCell(createHeaderCell(header, 1, 1));
            }
        }

        // 添加数据行
        for (ProjectTestStatisticsDTO stat : statistics) {
            // 添加项目名称
            table.addCell(createCell(stat.getProjectName()));

            // 添加优秀人数
            table.addCell(createCell(String.valueOf(stat.getMaleExcellentCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleExcellentCount())));
            table.addCell(createCell(String.valueOf(stat.getExcellentTotalCount())));
            table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getExcellentRate()) + "%"));

            // 添加良好人数
            table.addCell(createCell(String.valueOf(stat.getMaleGoodCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleGoodCount())));
            table.addCell(createCell(String.valueOf(stat.getGoodTotalCount())));
            table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getGoodRate()) + "%"));

            // 添加及格人数
            table.addCell(createCell(String.valueOf(stat.getMalePassCount())));
            table.addCell(createCell(String.valueOf(stat.getFemalePassCount())));
            table.addCell(createCell(String.valueOf(stat.getPassTotalCount())));
            table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getPassRate()) + "%"));

            // 添加不及格人数
            table.addCell(createCell(String.valueOf(stat.getMaleFailCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleFailCount())));
            table.addCell(createCell(String.valueOf(stat.getFailTotalCount())));
            table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getFailRate()) + "%"));
        }

        document.add(table);
    }

    private void addProjectStatisticsTable(Document document, List<ProjectTestStatisticsDTO> statistics) {
        // 添加表格标题
        Paragraph title = new Paragraph("各个项目测试人数及免测人数统计表")
                .setFontSize(16)
                .setTextAlignment(TextAlignment.CENTER)
                .setBold()
                .setMarginBottom(20);
        document.add(title);

        // 创建表格
        float[] columnWidths = {200, 60, 60, 80, 60, 60, 80, 60, 60, 80, 60};
        Table table = new Table(UnitValue.createPointArray(columnWidths));
        table.setWidth(UnitValue.createPercentValue(100))
            .setHorizontalAlignment(HorizontalAlignment.CENTER)
            .setMarginTop(10)
            .setMarginBottom(10);

        // 添加表头（第一行）
        table.addCell(createHeaderCell("项目名称", 2, 1));
        table.addCell(createHeaderCell("学生人数", 1, 3));
        table.addCell(createHeaderCell("实测学生数", 1, 3));
        table.addCell(createHeaderCell("申请免测学生数", 1, 4));
//        table.addCell(createHeaderCell("占%", 2, 1));

        // 添加表头（第二行）
        String[] subHeaders = {"男", "女", "合计", "男", "女", "合计", "男", "女", "合计","占%"};
        for (String header : subHeaders) {
            table.addCell(createHeaderCell(header, 1, 1));
        }

        // 添加数据行
        for (ProjectTestStatisticsDTO stat : statistics) {
            // 添加项目名称
            table.addCell(createCell(stat.getProjectName()));

            // 添加学生人数
            table.addCell(createCell(String.valueOf(stat.getMaleTotalCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleTotalCount())));
            table.addCell(createCell(String.valueOf(stat.getTotalCount())));

            // 添加实测学生数
            table.addCell(createCell(String.valueOf(stat.getMaleTestedCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleTestedCount())));
            table.addCell(createCell(String.valueOf(stat.getTestedTotalCount())));

            // 添加免测学生数
            table.addCell(createCell(String.valueOf(stat.getMaleExemptCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleExemptCount())));
            table.addCell(createCell(String.valueOf(stat.getExemptTotalCount())));

            // 添加免测率
            table.addCell(createCell(DECIMAL_FORMAT.format(stat.getExemptRate()) + "%"));
        }

        document.add(table);
    }

    @Override
    public List<BmiStatisticsDTO> getBmiStatistics(Integer planId, Integer schoolId) {
        Assert.notNull(planId, "计划ID不能为空");
        
        // 构建查询条件
        LambdaQueryWrapper<SummaryResult> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SummaryResult::getPlanId, planId);
        if (schoolId != null) {
            wrapper.eq(SummaryResult::getSchoolId, schoolId);
        }
        
        // 获取所有测试结果
        List<SummaryResult> allResults = summaryResultService.list(wrapper);
        
        // 根据schoolId决定按学校还是按年级分组
        Map<String, List<SummaryResult>> groupedResults;
        if (schoolId != null) {
            // 按年级分组，并使用年级名称
            groupedResults = allResults.stream()
                    .collect(Collectors.groupingBy(r -> GradeUtil.getGradeName(r.getGradeId())));
        } else {
            // 按学校分组
            groupedResults = allResults.stream()
                    .collect(Collectors.groupingBy(SummaryResult::getSchoolName));
        }
        
        List<BmiStatisticsDTO> statistics = new ArrayList<>();
        
        // 处理每个学校的统计数据
        for (Map.Entry<String, List<SummaryResult>> entry : groupedResults.entrySet()) {
            String schoolName = entry.getKey();
            List<SummaryResult> results = entry.getValue();
            
            BmiStatisticsDTO dto = new BmiStatisticsDTO();
            dto.setSchoolName(schoolName);
            
            // 统计性别数据
            long maleCount = results.stream().filter(r -> "1".equals(r.getSex())).count();
            long femaleCount = results.stream().filter(r -> "2".equals(r.getSex())).count();
            
            dto.setMaleTotalCount((int) maleCount);
            dto.setFemaleTotalCount((int) femaleCount);
            dto.setTotalCount((int) (maleCount + femaleCount));
            
            // 统计实测人数和各BMI等级人数
            for (SummaryResult result : results) {
                if (result.getTestResultList() == null) {
                    continue;
                }

                String sex = result.getSex();
                boolean isMale = "1".equals(sex);
                boolean isFemale = "2".equals(sex);
                
                // 查找身高体重项目的测试结果
                Optional<TestResult> bmiResult = result.getTestResultList().stream()
                        .filter(tr -> "BMI".equals(tr.getPrjName()))
                        .findFirst();
                
                if (bmiResult.isPresent() && bmiResult.get().getResult() != null && !bmiResult.get().getResult().trim().isEmpty()) {
                    // 更新实测人数
                    if (isMale) {
                        dto.setMaleTestedCount(dto.getMaleTestedCount() + 1);
                    } else if (isFemale) {
                        dto.setFemaleTestedCount(dto.getFemaleTestedCount() + 1);
                    }
                    
                    // 获取BMI等级并更新统计
                    String level = bmiResult.get().getLevel();
                    if (level != null) {
                        switch (level) {
                            case "肥胖":
                                if (isMale) dto.setMaleObeseCount(dto.getMaleObeseCount() + 1);
                                else if (isFemale) dto.setFemaleObeseCount(dto.getFemaleObeseCount() + 1);
                                break;
                            case "超重":
                                if (isMale) dto.setMaleOverweightCount(dto.getMaleOverweightCount() + 1);
                                else if (isFemale) dto.setFemaleOverweightCount(dto.getFemaleOverweightCount() + 1);
                                break;
                            case "正常":
                                if (isMale) dto.setMaleNormalCount(dto.getMaleNormalCount() + 1);
                                else if (isFemale) dto.setFemaleNormalCount(dto.getFemaleNormalCount() + 1);
                                break;
                            case "低体重":
                                if (isMale) dto.setMaleUnderweightCount(dto.getMaleUnderweightCount() + 1);
                                else if (isFemale) dto.setFemaleUnderweightCount(dto.getFemaleUnderweightCount() + 1);
                                break;
                        }
                    }
                }
            }
            
            // 更新总测试人数
            dto.setTestedTotalCount(dto.getMaleTestedCount() + dto.getFemaleTestedCount());
            
            // 计算各等级总人数
            dto.setObeseTotalCount(dto.getMaleObeseCount() + dto.getFemaleObeseCount());
            dto.setOverweightTotalCount(dto.getMaleOverweightCount() + dto.getFemaleOverweightCount());
            dto.setNormalTotalCount(dto.getMaleNormalCount() + dto.getFemaleNormalCount());
            dto.setUnderweightTotalCount(dto.getMaleUnderweightCount() + dto.getFemaleUnderweightCount());
            
            // 计算比率
            if (dto.getTestedTotalCount() > 0) {
                dto.setObeseRate((double) dto.getObeseTotalCount() / dto.getTestedTotalCount() * 100);
                dto.setOverweightRate((double) dto.getOverweightTotalCount() / dto.getTestedTotalCount() * 100);
                dto.setNormalRate((double) dto.getNormalTotalCount() / dto.getTestedTotalCount() * 100);
                dto.setUnderweightRate((double) dto.getUnderweightTotalCount() / dto.getTestedTotalCount() * 100);
            }
            
            statistics.add(dto);
        }
        
        // 如果是按年级统计，则按年级排序
        if (schoolId != null) {
            // 创建年级顺序映射
            Map<String, Integer> gradeOrder = new HashMap<>();
            gradeOrder.put("初一", 1);
            gradeOrder.put("初二", 2);
            gradeOrder.put("初三", 3);
            
            statistics.sort((a, b) -> {
                // 获取年级顺序值，如果不在映射中则返回最大值
                int orderA = gradeOrder.getOrDefault(a.getSchoolName(), Integer.MAX_VALUE);
                int orderB = gradeOrder.getOrDefault(b.getSchoolName(), Integer.MAX_VALUE);
                
                return Integer.compare(orderA, orderB);
            });
        }
        
        return statistics;
    }

    private void addBmiDistributionTable(Document document, List<BmiStatisticsDTO> statistics) {
        // 添加表格标题
        Paragraph title = new Paragraph("BMI等级分布统计表")
                .setFontSize(16)
                .setTextAlignment(TextAlignment.CENTER)
                .setBold()
                .setMarginBottom(20);
        document.add(title);

        // 创建表格
        float[] columnWidths = {200, 60, 60, 60, 40, 60, 60, 60, 40, 60, 60, 60, 40, 60, 60, 60, 40};
        Table table = new Table(UnitValue.createPointArray(columnWidths));
        table.setWidth(UnitValue.createPercentValue(100))
            .setHorizontalAlignment(HorizontalAlignment.CENTER)
            .setMarginTop(10)
            .setMarginBottom(10);

        // 添加表头（第一行）
        table.addCell(createHeaderCell("单位", 2, 1));
        table.addCell(createHeaderCell("肥胖", 1, 4));
        table.addCell(createHeaderCell("超重", 1, 4));
        table.addCell(createHeaderCell("正常", 1, 4));
        table.addCell(createHeaderCell("低体重", 1, 4));

        // 添加表头（第二行）
        String[] subHeaders = {"男", "女", "合计", "占%"};
        for (int i = 0; i < 4; i++) {
            for (String header : subHeaders) {
                table.addCell(createHeaderCell(header, 1, 1));
            }
        }

        // 添加数据行
        for (BmiStatisticsDTO stat : statistics) {
            // 添加学校名称
            table.addCell(createCell(stat.getSchoolName()));

            // 添加肥胖人数
            table.addCell(createCell(String.valueOf(stat.getMaleObeseCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleObeseCount())));
            table.addCell(createCell(String.valueOf(stat.getObeseTotalCount())));
            table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getObeseRate()) + "%"));

            // 添加超重人数
            table.addCell(createCell(String.valueOf(stat.getMaleOverweightCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleOverweightCount())));
            table.addCell(createCell(String.valueOf(stat.getOverweightTotalCount())));
            table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getOverweightRate()) + "%"));

            // 添加正常人数
            table.addCell(createCell(String.valueOf(stat.getMaleNormalCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleNormalCount())));
            table.addCell(createCell(String.valueOf(stat.getNormalTotalCount())));
            table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getNormalRate()) + "%"));

            // 添加低体重人数
            table.addCell(createCell(String.valueOf(stat.getMaleUnderweightCount())));
            table.addCell(createCell(String.valueOf(stat.getFemaleUnderweightCount())));
            table.addCell(createCell(String.valueOf(stat.getUnderweightTotalCount())));
            table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getUnderweightRate()) + "%"));
        }

        document.add(table);
    }

    private void addBmiPieCharts(Document document, List<BmiStatisticsDTO> statistics, boolean isGradeLevel) {
        // 添加标题
        for (int i = 0; i < statistics.size(); i++) {
            // 每个图表前都添加分页
            document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));

            BmiStatisticsDTO stat = statistics.get(i);
            // 修改标题显示逻辑，无论是否有schoolId，都显示具体的学校/年级名称
            String titleText = stat.getSchoolName() + "BMI等级分布饼图";
            Paragraph title = new Paragraph(titleText)
                    .setFontSize(16)
                    .setTextAlignment(TextAlignment.CENTER)
                    .setBold()
                    .setMarginBottom(20);
            document.add(title);

            float chartSize = 300f; // 增大饼图大小
            float legendWidth = 150f; // 增大图例宽度

            // 创建单个学校的图表容器
            Table chartTable = new Table(1);
            chartTable.setWidth(UnitValue.createPercentValue(100))
                    .setHorizontalAlignment(HorizontalAlignment.CENTER)
                    .setBorder(Border.NO_BORDER);

            // 创建饼图和图例的容器
            Cell chartCell = new Cell()
                    .setBorder(Border.NO_BORDER)
                    .setPadding(5)
                    .setHeight(chartSize + 50); // 设置足够的高度

            // 计算饼图数据
            double[] values = {
                stat.getObeseTotalCount(),
                stat.getOverweightTotalCount(),
                stat.getNormalTotalCount(),
                stat.getUnderweightTotalCount()
            };
            String[] labels = {"肥胖", "超重", "正常", "低体重"};

            // 创建自定义渲染器来绘制饼图
            chartCell.setNextRenderer(new PieChartCellRenderer(chartCell, values, labels, BMI_CHART_COLORS, chartSize));

            chartTable.addCell(chartCell);
            document.add(chartTable);
        }
    }

    private static class PieChartCellRenderer extends CellRenderer {
        private final double[] values;
        private final String[] labels;
        private final DeviceRgb[] colors;
        private final float chartSize;
        private PdfFont font;

        public PieChartCellRenderer(Cell modelElement, double[] values, String[] labels, DeviceRgb[] colors, float chartSize) {
            super(modelElement);
            this.values = values;
            this.labels = labels;
            this.colors = colors;
            this.chartSize = chartSize;
            try {
                this.font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
            } catch (IOException e) {
                throw new RuntimeException("创建字体失败", e);
            }
        }

        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);

            // 获取单元格边界
            Rectangle cellRect = getOccupiedArea().getBBox();
            
            // 计算饼图中心点（水平居中）
            float centerX = cellRect.getLeft() + cellRect.getWidth() / 2;
            float centerY = cellRect.getBottom() + cellRect.getHeight() / 2;
            float radius = chartSize / 2 - 10;

            PdfCanvas canvas = drawContext.getCanvas();
            
            // 计算总和
            double total = Arrays.stream(values).sum();
            if (total <= 0) return;

            // 绘制饼图
            float startAngle = 90;
            for (int i = 0; i < values.length; i++) {
                if (values[i] <= 0) continue;

                // 计算扇形角度
                float sweepAngle = (float) (values[i] / total * 360);
                
                // 绘制扇形
                canvas.saveState()
                      .setFillColor(colors[i])
                      .moveTo(centerX, centerY)
                      .arc(centerX - radius, centerY - radius,
                           centerX + radius, centerY + radius,
                           startAngle, -sweepAngle)
                      .lineTo(centerX, centerY)
                      .fill()
                      .restoreState();

                // 计算扇形中心点的角度（用于放置文本）
                double midAngle = Math.toRadians(startAngle - sweepAngle / 2);
                float textRadius = radius * 0.7f; // 文本距离中心点的距离
                float textX = centerX + (float) (Math.cos(midAngle) * textRadius);
                float textY = centerY + (float) (Math.sin(midAngle) * textRadius);

                // 绘制数值
                String valueText = String.format("%d人", (int)values[i]);
                canvas.saveState()
                      .setFillColor(ColorConstants.WHITE)
                      .setStrokeColor(ColorConstants.WHITE)
                      .beginText()
                      .setFontAndSize(font, 10)
                      .moveText(textX - (valueText.length() * 5), textY - 5)
                      .showText(valueText)
                      .endText()
                      .restoreState();

                // 绘制图例
                float legendX = centerX + radius + 20;
                float legendY = centerY + radius - (i * 25); // 增加图例间距
                
                // 绘制图例色块
                canvas.saveState()
                      .setFillColor(colors[i])
                      .rectangle(legendX, legendY - 8, 12, 12)
                      .fill()
                      .restoreState();

                // 绘制图例文本
                String legendText = String.format("%s: %d人 (%.1f%%)", 
                    labels[i], 
                    (int)values[i], 
                    values[i] / total * 100);
                canvas.saveState()
                      .setStrokeColor(ColorConstants.BLACK)
                      .setFillColor(ColorConstants.BLACK)
                      .beginText()
                      .setFontAndSize(font, 10)
                      .moveText(legendX + 15, legendY - 5)
                      .showText(legendText)
                      .endText()
                      .restoreState();

                startAngle -= sweepAngle;
            }
        }

        @Override
        public IRenderer getNextRenderer() {
            return new PieChartCellRenderer((Cell) getModelElement(), values, labels, colors, chartSize);
        }
    }

    @Override
    public List<ProjectSchoolStatisticsDTO> getProjectSchoolStatistics(Integer planId, Integer schoolId) {
        Assert.notNull(planId, "计划ID不能为空");
        
        // 构建查询条件
        LambdaQueryWrapper<SummaryResult> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SummaryResult::getPlanId, planId);
        if (schoolId != null) {
            wrapper.eq(SummaryResult::getSchoolId, schoolId);
        }
        
        // 获取所有测试结果
        List<SummaryResult> allResults = summaryResultService.list(wrapper);
        
        // 创建项目-学校/年级统计结果Map
        Map<String, Map<String, ProjectSchoolStatisticsDTO>> projectStatsMap = new HashMap<>();
        
        // 定义需要排除的项目名称
        Set<String> excludedProjects = new HashSet<>(Arrays.asList("身高", "体重", "身高体重", "BMI"));
        
        // 处理每个学生的测试结果
        for (SummaryResult result : allResults) {
            if (result.getTestResultList() == null) {
                continue;
            }
            
            // 根据schoolId决定使用学校名称还是年级作为分组键
            String groupKey;
            if (schoolId != null) {
                // 使用年级名称作为分组键
                groupKey = GradeUtil.getGradeName(result.getGradeId());
            } else {
                groupKey = result.getSchoolName();
            }
            
            String sex = result.getSex();
            boolean isMale = "1".equals(sex);
            boolean isFemale = "2".equals(sex);
            
            // 处理每个项目的测试结果
            for (TestResult testResult : result.getTestResultList()) {
                String projectName = testResult.getPrjName();
                
                // 跳过需要排除的项目
                if (excludedProjects.contains(projectName)) {
                    continue;
                }
                
                // 获取或创建项目Map
                Map<String, ProjectSchoolStatisticsDTO> statsMap = projectStatsMap
                    .computeIfAbsent(projectName, k -> new HashMap<>());
                
                // 获取或创建统计DTO
                ProjectSchoolStatisticsDTO stats = statsMap.computeIfAbsent(
                    groupKey,
                    k -> {
                        ProjectSchoolStatisticsDTO dto = new ProjectSchoolStatisticsDTO();
                        dto.setProjectName(projectName);
                        dto.setSchoolName(k);
                        return dto;
                    }
                );
                
                // 更新统计数据
                if (testResult.getResult() != null && !testResult.getResult().trim().isEmpty()) {
                    stats.setTestedTotalCount(stats.getTestedTotalCount() + 1);
                    
                    String level = testResult.getLevel();
                    if (level != null) {
                        switch (level) {
                            case "优秀":
                                if (isMale) stats.setMaleExcellentCount(stats.getMaleExcellentCount() + 1);
                                else if (isFemale) stats.setFemaleExcellentCount(stats.getFemaleExcellentCount() + 1);
                                break;
                            case "良好":
                                if (isMale) stats.setMaleGoodCount(stats.getMaleGoodCount() + 1);
                                else if (isFemale) stats.setFemaleGoodCount(stats.getFemaleGoodCount() + 1);
                                break;
                            case "及格":
                                if (isMale) stats.setMalePassCount(stats.getMalePassCount() + 1);
                                else if (isFemale) stats.setFemalePassCount(stats.getFemalePassCount() + 1);
                                break;
                            case "不及格":
                                if (isMale) stats.setMaleFailCount(stats.getMaleFailCount() + 1);
                                else if (isFemale) stats.setFemaleFailCount(stats.getFemaleFailCount() + 1);
                                break;
                        }
                    }
                }
            }
        }
        
        // 计算总数和比率，并转换为列表
        List<ProjectSchoolStatisticsDTO> result = new ArrayList<>();
        for (Map.Entry<String, Map<String, ProjectSchoolStatisticsDTO>> projectEntry : projectStatsMap.entrySet()) {
            for (ProjectSchoolStatisticsDTO stats : projectEntry.getValue().values()) {
                // 计算总数
                stats.setExcellentTotalCount(stats.getMaleExcellentCount() + stats.getFemaleExcellentCount());
                stats.setGoodTotalCount(stats.getMaleGoodCount() + stats.getFemaleGoodCount());
                stats.setPassTotalCount(stats.getMalePassCount() + stats.getFemalePassCount());
                stats.setFailTotalCount(stats.getMaleFailCount() + stats.getFemaleFailCount());
                
                // 计算总测试人数
                stats.setTestedTotalCount(stats.getExcellentTotalCount() + stats.getGoodTotalCount() + 
                                        stats.getPassTotalCount() + stats.getFailTotalCount());
                
                // 计算比率，使用实测人数作为分母
                if (stats.getTestedTotalCount() > 0) {
                    stats.setExcellentRate((double) stats.getExcellentTotalCount() / stats.getTestedTotalCount() * 100);
                    stats.setGoodRate((double) stats.getGoodTotalCount() / stats.getTestedTotalCount() * 100);
                    stats.setPassRate((double) stats.getPassTotalCount() / stats.getTestedTotalCount() * 100);
                    stats.setFailRate((double) stats.getFailTotalCount() / stats.getTestedTotalCount() * 100);
                }
                
                result.add(stats);
            }
        }
        
        // 如果是按年级统计，则按年级排序
        if (schoolId != null) {
            // 创建年级顺序映射
            Map<String, Integer> gradeOrder = new HashMap<>();
            gradeOrder.put("初一", 1);
            gradeOrder.put("初二", 2);
            gradeOrder.put("初三", 3);
            
            result.sort((a, b) -> {
                // 获取年级顺序值，如果不在映射中则返回最大值
                int orderA = gradeOrder.getOrDefault(a.getSchoolName(), Integer.MAX_VALUE);
                int orderB = gradeOrder.getOrDefault(b.getSchoolName(), Integer.MAX_VALUE);
                
                return Integer.compare(orderA, orderB);
            });
        }
        
        return result;
    }

    private void addProjectSchoolStatisticsTable(Document document, List<ProjectSchoolStatisticsDTO> statistics, boolean isGradeLevel) {
        // 按项目分组统计数据
        Map<String, List<ProjectSchoolStatisticsDTO>> projectGroups = statistics.stream()
                .collect(Collectors.groupingBy(ProjectSchoolStatisticsDTO::getProjectName));
        
        // 为每个项目创建一个表格
        for (Map.Entry<String, List<ProjectSchoolStatisticsDTO>> entry : projectGroups.entrySet()) {
            String projectName = entry.getKey();
            List<ProjectSchoolStatisticsDTO> projectStats = entry.getValue();
            
            // 添加项目标题
            String titleText = projectName + (isGradeLevel ? "各年级测试等级分布统计表" : "各学校测试等级分布统计表");
            Paragraph title = new Paragraph(titleText)
                    .setFontSize(14)
                    .setTextAlignment(TextAlignment.CENTER)
                    .setBold()
                    .setMarginBottom(10)
                    .setMarginTop(20);
            document.add(title);
            
            // 创建表格
            float[] columnWidths = {200, 60, 60, 60, 40, 60, 60, 60, 40, 60, 60, 60, 40, 60, 60, 60, 40};
            Table table = new Table(UnitValue.createPointArray(columnWidths));
            table.setWidth(UnitValue.createPercentValue(100))
                .setHorizontalAlignment(HorizontalAlignment.CENTER)
                .setMarginTop(10)
                .setMarginBottom(10);
            
            // 添加表头（第一行）
            table.addCell(createHeaderCell(isGradeLevel ? "年级" : "单位", 2, 1));
            table.addCell(createHeaderCell("优秀人数", 1, 4));
            table.addCell(createHeaderCell("良好人数", 1, 4));
            table.addCell(createHeaderCell("及格人数", 1, 4));
            table.addCell(createHeaderCell("不及格人数", 1, 4));
            
            // 添加表头（第二行）
            String[] subHeaders = {"男", "女", "合计", "占%"};
            for (int i = 0; i < 4; i++) {
                for (String header : subHeaders) {
                    table.addCell(createHeaderCell(header, 1, 1));
                }
            }
            
            // 添加数据行
            for (ProjectSchoolStatisticsDTO stat : projectStats) {
                // 添加学校名称或年级
                table.addCell(createCell(stat.getSchoolName()));
                
                // 添加优秀人数
                table.addCell(createCell(String.valueOf(stat.getMaleExcellentCount())));
                table.addCell(createCell(String.valueOf(stat.getFemaleExcellentCount())));
                table.addCell(createCell(String.valueOf(stat.getExcellentTotalCount())));
                table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getExcellentRate()) + "%"));
                
                // 添加良好人数
                table.addCell(createCell(String.valueOf(stat.getMaleGoodCount())));
                table.addCell(createCell(String.valueOf(stat.getFemaleGoodCount())));
                table.addCell(createCell(String.valueOf(stat.getGoodTotalCount())));
                table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getGoodRate()) + "%"));
                
                // 添加及格人数
                table.addCell(createCell(String.valueOf(stat.getMalePassCount())));
                table.addCell(createCell(String.valueOf(stat.getFemalePassCount())));
                table.addCell(createCell(String.valueOf(stat.getPassTotalCount())));
                table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getPassRate()) + "%"));
                
                // 添加不及格人数
                table.addCell(createCell(String.valueOf(stat.getMaleFailCount())));
                table.addCell(createCell(String.valueOf(stat.getFemaleFailCount())));
                table.addCell(createCell(String.valueOf(stat.getFailTotalCount())));
                table.addCell(createPercentageCell(DECIMAL_FORMAT.format(stat.getFailRate()) + "%"));
            }
            
            document.add(table);
        }
    }

    private String formatNumber(Double value) {
        if (value == null || value.isNaN()) {
            return "-";
        }
        try {
            return DECIMAL_FORMAT.format(value);
        } catch (Exception e) {
            return "-";
        }
    }

    private String formatPercentage(Double value) {
        if (value == null || value.isNaN()) {
            return "-";
        }
        try {
            return DECIMAL_FORMAT.format(value) + "%";
        } catch (Exception e) {
            return "-";
        }
    }

    private void addAverageScoreTable(Document document, List<SchoolTestStatisticsDTO> statistics, boolean isGradeLevel) {
        // 添加表格标题
        String titleText = isGradeLevel ? "各年级平均分、优良率、合格率统计" : "各学校平均分、优良率、合格率统计";
        Paragraph title = new Paragraph(titleText)
                .setFontSize(16)
                .setTextAlignment(TextAlignment.CENTER)
                .setBold()
                .setMarginBottom(20);
        document.add(title);

        // 创建表格
        float[] columnWidths = {200, 80, 80, 80, 80, 80};
        Table table = new Table(UnitValue.createPointArray(columnWidths));
        table.setWidth(UnitValue.createPercentValue(100))
            .setHorizontalAlignment(HorizontalAlignment.CENTER)
            .setMarginTop(10)
            .setMarginBottom(10);

        // 添加表头
        table.addCell(createHeaderCell(isGradeLevel ? "年级" : "单位", 1, 1));
        table.addCell(createHeaderCell("男生平均分", 1, 1));
        table.addCell(createHeaderCell("女生平均分", 1, 1));
        table.addCell(createHeaderCell("总平均分", 1, 1));
        table.addCell(createHeaderCell("优良率", 1, 1));
        table.addCell(createHeaderCell("合格率", 1, 1));

        // 添加数据行
        for (SchoolTestStatisticsDTO stat : statistics) {
            table.addCell(createCell(stat.getSchoolName()));
            
            // 处理平均分，如果为空则显示 "-"
            table.addCell(createCell(formatNumber(stat.getMaleAvgScore())));
            table.addCell(createCell(formatNumber(stat.getFemaleAvgScore())));
            table.addCell(createCell(formatNumber(stat.getTotalAvgScore())));
            
            // 处理百分比，如果为空则显示 "-"
            table.addCell(createPercentageCell(formatPercentage(stat.getExcellentRate())));
            table.addCell(createPercentageCell(formatPercentage(stat.getPassRate())));
        }

        document.add(table);
    }

    private String getSchoolNameById(Integer schoolId) {
        // 使用 schoolService.getById() 获取学校名称
        School school = schoolService.getById(schoolId);
        return school != null ? school.getName() : "未知学校";
    }

    // 添加辅助方法：判断测试结果是否有效
    private boolean isValidTestResult(TestResult result) {
        return result != null && 
               result.getResult() != null && 
               !result.getResult().trim().isEmpty() && 
               result.getLevel() != null;
    }

    // 添加数据一致性检查方法
    private void validateStatistics(ProjectSchoolStatisticsDTO stats) {
        // 检查总数是否正确
        int calculatedTotal = stats.getExcellentTotalCount() + 
                             stats.getGoodTotalCount() + 
                             stats.getPassTotalCount() + 
                             stats.getFailTotalCount();
        
        if (calculatedTotal != stats.getTestedTotalCount()) {
            log.warn("Statistics inconsistency detected for project {} in {}: " +
                    "sum of all levels ({}) != tested total ({})", 
                    stats.getProjectName(), stats.getSchoolName(), 
                    calculatedTotal, stats.getTestedTotalCount());
        }
        
        // 检查比率总和是否接近 100%
        double totalRate = stats.getExcellentRate() + 
                          stats.getGoodRate() + 
                          stats.getPassRate() + 
                          stats.getFailRate();
        
        if (Math.abs(totalRate - 100.0) > 0.1) { // 允许 0.1% 的误差
            log.warn("Rate sum inconsistency detected for project {} in {}: " +
                    "total rate = {}%", 
                    stats.getProjectName(), stats.getSchoolName(), 
                    totalRate);
        }
    }
} 